#include <linux/notifier.h>  
#include <linux/module.h>  
#include <linux/init.h>  
#include <linux/kernel.h> 
#include <linux/fs.h> 

struct atomic_notifier_head	my_notifier_chain;
EXPORT_SYMBOL(my_notifier_chain);


int nb1_notifier_call(struct notifier_block *nb, unsigned long action, void *data)
{
    printk("%s, %lu\n", __func__, action);

    return 0;
}

struct notifier_block nb1 = {
    .notifier_call = nb1_notifier_call,
    .priority = 3,
};
struct notifier_block nb2 = {
    .notifier_call = nb1_notifier_call,
    .priority = 1,
};
struct notifier_block nb3 = {
    .notifier_call = nb1_notifier_call,
    .priority = 2,
};


static int __init notifier_chain_recv_init(void)
{
    ATOMIC_INIT_NOTIFIER_HEAD(&my_notifier_chain);

    // printk("head = %p\n", my_notifier_chain.head);  head = NULL

    atomic_notifier_chain_register(&my_notifier_chain, &nb1);
    atomic_notifier_chain_register(&my_notifier_chain, &nb2);
    atomic_notifier_chain_register(&my_notifier_chain, &nb3);

    // 结合下面的打印去分析notifier_chain_register函数的实现，难点是如何实现priority的排序的
    // printk("&nb1 = %p\n", &nb1);
    // printk("&nb2 = %p\n", &nb2);
    // printk("&nb3 = %p\n", &nb3);
    // printk("0x%p, 0x%p, 0x%p\n", my_notifier_chain.head, my_notifier_chain.head->next, my_notifier_chain.head->next->next);

    return 0;
}

static void __exit notifier_chain_recv_exit(void)
{
    atomic_notifier_chain_unregister(&my_notifier_chain, &nb1);
    atomic_notifier_chain_unregister(&my_notifier_chain, &nb2);
    atomic_notifier_chain_unregister(&my_notifier_chain, &nb3);
}

module_init(notifier_chain_recv_init);
module_exit(notifier_chain_recv_exit);
MODULE_LICENSE("GPL v2");
